using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Xml.Serialization;
using System.IO;

namespace Dida
{
	/// <summary>
	/// A vector in a 2 dimensional space.
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	[DebuggerDisplay("Vector2D({x}, {y})")]
	public struct Vector2D : IXmlSerializable
	{
		/// <summary>
		/// The x component of this vector.
		/// </summary>
		public float x;
		/// <summary>
		/// The y component of this vector.
		/// </summary>
		public float y;

		/// <summary>
		/// Creates a new <see cref = "Vector2D">Vector2D</see>, initialized
		/// with the given values.
		/// </summary>
		/// <param name="x">The initial value for the x component.</param>
		/// <param name="y">The initial value for the y component.</param>
		public Vector2D(float x, float y)
		{
			this.x = x;
			this.y = y;
		}

		/// <summary>
		/// Sets this vector's components to the given values.
		/// </summary>
		/// <param name="x">The new value for the x component.</param>
		/// <param name="y">The new value for the y component</param>
		public void Set(float x, float y)
		{
			this.x = x;
			this.y = y;
		}

		/// <summary>
		/// Indexes the components of the vector using an array indexer, where
		/// index 0 = x and index 1 = y. Any other index is invalid.
		/// </summary>
		public float this[int i]
		{
			get
			{
				Debug.Assert(i >= 0 && i < 2, "Invalid index");

#if SECURE
				if (i == 0)
					return x;
				else 
					return y;
#else
#if PROTECTED
				if (i < 0 || i > 1)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector2D* p = &this)
					{
						return ((float*)p)[i];
					}
				}
#endif
			}

			set
			{
				Debug.Assert(i >= 0 && i < 2, "Invalid index");

#if SECURE
				if (i == 0)
					x = value;
				else
					y = value;
#else
#if PROTECTED
				if (i < 0 || i > 1)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector2D* p = &this)
					{
						((float*)p)[i] = value;
					}
				}
#endif
			}
		}

		/// <summary>
		/// Adds the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the addition.</returns>
		public static Vector2D operator +(Vector2D a,Vector2D b)
		{
			return new Vector2D(a.x + b.x, a.y + b.y);
		}

		/// <summary>
		/// Subtracts the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the subtraction.</returns>
		public static Vector2D operator -(Vector2D a, Vector2D b)
		{
			return new Vector2D(a.x - b.x, a.y - b.y);
		}

		/// <summary>
		/// Multiplies the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the multiplication.</returns>
		public static Vector2D operator *(Vector2D a, float b)
		{
			return new Vector2D(a.x * b, a.y * b);
		}

		/// <summary>
		/// Divides the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the division.</returns>
		public static Vector2D operator /(Vector2D a, float b)
		{
			float recib = 1 / b;
			return new Vector2D(a.x * recib, a.y * recib);
		}

		public static Vector2D operator -(Vector2D a)
		{
			return new Vector2D(-a.x, -a.y);
		}

		/// <summary>
		/// Gets the length of this vector
		/// </summary>
		public float Len
		{
			get
			{
				return (float)Math.Sqrt(x * x + y * y);
			}
		}

		/// <summary>
		/// Gets the squared length of this vector (Len ^ 2)
		/// </summary>
		public float SqrLen
		{
			get
			{
				return x * x + y * y;
			}
		}

		/// <summary>
		/// Normalizes this vector. ie. It will be scaled, so that it's
		/// length will be 1.
		/// </summary>
		public void Normalize()
		{
			float scale = 1 / (float)Math.Sqrt(x * x + y * y);
			x *= scale;
			y *= scale;
		}

		/// <summary>
		/// Scales this vector, so that it's length will be the given length.
		/// </summary>
		/// <param name="len">The length to scale this vector to.</param>
		public void Scale(float len)
		{
			float scale = len / (float)Math.Sqrt(x * x + y * y);
			x *= scale;
			y *= scale;
		}

		/// <summary>
		/// Calculates the dotproduct between the 2 2D vectors.
		/// </summary>
		/// <param name="a">The first operand</param>
		/// <param name="b">The second operand</param>
		/// <returns>The result of the dotproduct operation.</returns>
		public static float DotProduct(Vector2D a, Vector2D b)
		{
			return a.x * b.x + a.y * b.y;
		}

		/// <summary>
		/// Calculates the perpendicular dot product. That is, the vector in a
		/// is rotated by 90 degrees in the counter clockwise, and then the 
		/// dot product between that rotated vector, and the vector in b is calculated.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the perpendicular dot product operation.</returns>
		public static float PerpDotProduct(Vector2D a, Vector2D b)
		{
			return a.x * b.y - a.y * b.x;
		}

		public static Vector2D Interpolate(Vector2D a, Vector2D b, float t)
		{
			return a + (b - a) * t;
		}

		public void Rotate90DegCCW()
		{
			float tmp;
			tmp = y;
			y = x;
			x = -tmp;
		}

		public void Rotate90DegCW()
		{
			float tmp;
			tmp = y;
			y = -x;
			x = tmp;
		}

		/// <summary>
		/// Returns the angle from a to b. This angle is in counter 
		/// clockwise direction, and always in the -PI - PI range.
		/// measured in the counter clockwise direction.
		/// </summary>
		/// <param name="a">The vector from where the angle should be
		/// calculated. It doesn't have to be normalized.</param>
		/// <param name="b">The vector to where the angle should be
		/// calculated. It doesn't have to be normalized</param>
		/// <returns>The angle from a to b.</returns>
		public static float GetAngle(Vector2D a, Vector2D b)
		{
			a.Normalize();
			b.Normalize();

			float dot = DotProduct(a, b);
			if (dot > 1)
				return 0;
			else if (dot < -1)
				return (float)Math.PI;
			
			float angle = (float)Math.Acos(dot);
			float perpDot = PerpDotProduct(a, b);
			if (perpDot > 0)
				return angle;
			else
				return -angle;
		}

		/// <summary>
		/// Returns a unit vector that's rotated by the given angle
		/// from the vector (1,0), in counter clockwise direction.
		/// </summary>
		/// <param name="angle">The angle of the vector, in radians.</param>
		/// <returns>A vector that specifies the given angle.</returns>
		public static Vector2D FromAngle(float angle)
		{
			return new Vector2D((float)Math.Cos(angle), (float)Math.Sin(angle));
		}

		/// <summary>
		/// Gets a string representation of this vector.
		/// </summary>
		/// <returns>The string representation of this vector.</returns>
		public override string ToString()
		{
			return x.ToString(CultureInfo.InvariantCulture) + ", " +
				y.ToString(CultureInfo.InvariantCulture);
		}

		[ParseMethod]
		public static Vector2D Parse(string s)
		{
			string[] splitted = s.Split(",".ToCharArray());
			if (splitted.Length != 2)
				throw new Exception("A 2D vector should have 2 components.");

			return new Vector2D(
				float.Parse(splitted[0], CultureInfo.InvariantCulture),
				float.Parse(splitted[1], CultureInfo.InvariantCulture));
		}

		#region IXmlSerializable Members

		public System.Xml.Schema.XmlSchema GetSchema()
		{
			return null;
		}

		public void ReadXml(System.Xml.XmlReader reader)
		{
			Vector2D v = Parse(reader.ReadString());
			x = v.x;
			y = v.y;
		}

		public void WriteXml(System.Xml.XmlWriter writer)
		{
			writer.WriteString(ToString());
		}

		#endregion
	}

	/// <summary>
	/// A vector in a 3 dimensional space.
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	[Dxml.Parsable]
	[DebuggerDisplay("Vector3D({x}, {y}, {z})")]
	public struct Vector3D
	{
		/// <summary>
		/// The x component of the vector.
		/// </summary>
		/// <remarks>
		/// In world space, this is the vector that points to the right,
		/// when looked at it through a camera with no rotation.
		/// </remarks>
		public float x;
		/// <summary>
		/// The y component of the vector.
		/// </summary>
		/// <remarks>
		/// In world space, this is the vector that points up,
		/// when looked at it through a camera with no rotation.
		/// </remarks>
		public float y;
		/// <summary>
		/// The z component of the vector.
		/// </summary>
		/// <remarks>
		/// In world space, this is the vector that points away from you,
		/// when looked at it through a camera with no rotation.
		/// </remarks>
		public float z;

		/// <summary>
		/// Indexes the components of the vector using an array indexer, where
		/// index 0 = x, index 1 = y and index 2 = z. Any other index is invalid.
		/// </summary>
		public float this[int i]
		{
			get
			{
				Debug.Assert(i >= 0 && i < 3, "Invalid index");

#if SECURE
				if (i == 0)
					return x;
				else if (i == 1)
					return y;
				else if(i == 2)
					return z;
				else
					throw new IndexOutOfRangeException();
#else
#if PROTECTED
				if (i < 0 || i > 2)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector3D* p = &this)
					{
						return ((float*)p)[i];
					}
				}
#endif
			}

			set
			{
				Debug.Assert(i >= 0 && i < 3, "Invalid index");

#if SECURE
				if (i == 0)
					x = value;
				else if (i == 1)
					y = value;
				else if(i == 2)
					z = value;
				else
					throw new IndexOutOfRangeException();
#else
#if PROTECTED
				if (i < 0 || i > 2)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector3D* p = &this)
					{
						((float*)p)[i] = value;
					}
				}
#endif
			}
		}

		/// <summary>
		/// Creates a vector, initialized with the given component values.
		/// </summary>
		/// <param name="x">The x component for the new vector</param>
		/// <param name="y">The y component for the new vector</param>
		/// <param name="z">The z component for the new vector</param>
		public Vector3D(float x, float y, float z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		/// <summary>
		/// Sets this vectors components to the given values.
		/// </summary>
		/// <param name="x">The new x value for this vector.</param>
		/// <param name="y">The new y value for this vector.</param>
		/// <param name="z">The new z value for this vector.</param>
		public void Set(float x, float y, float z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		/// <summary>
		/// Adds the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the addition.</returns>
		public static Vector3D operator +(Vector3D a, Vector3D b)
		{
			return new Vector3D(a.x + b.x, a.y + b.y, a.z + b.z);
		}

		/// <summary>
		/// Subtracts the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the subtraction.</returns>
		public static Vector3D operator -(Vector3D a, Vector3D b)
		{
			return new Vector3D(a.x - b.x, a.y - b.y, a.z - b.z);
		}

		/// <summary>
		/// Multiplies the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the multiplication.</returns>
		public static Vector3D operator *(Vector3D a, float b)
		{
			return new Vector3D(a.x * b, a.y * b, a.z * b);
		}

		/// <summary>
		/// Divides the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the division.</returns>
		public static Vector3D operator /(Vector3D a, float b)
		{
			float recib = 1 / b;
			return new Vector3D(a.x * recib, a.y * recib, a.z * recib);
		}

		/// <summary>
		/// Negates this vector.
		/// </summary>
		/// <param name="a">The vector to negate.</param>
		/// <returns>The negated version of a.</returns>
		public static Vector3D operator -(Vector3D a)
		{
			return new Vector3D(-a.x, -a.y, -a.z);
		}

		/// <summary>
		/// Compares two vectors for equality
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>True if the two vectors are equal, false otherwise.</returns>
		/// <remarks>
		/// Note that <i>no</i> floating point inaccuracy tolerance is used
		/// in this compare, so try to avoid comparing vectors directly as much as possible,
		/// or use the <see cref = "CompareUsingTolerance(Vector3D,Vector3D,float)"/>
		/// method instead.
		/// </remarks>
		public static bool operator ==(Vector3D a, Vector3D b)
		{
			return a.x == b.x && a.y == b.y && a.z == b.z;
		}

		/// <summary>
		/// Compares two vectors for inequality.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>False if the two vectors are equal, true otherwise.</returns>
		/// <remarks>
		/// Note that <i>no</i> floating point inaccuracy tolerance is used
		/// in this compare, so try to avoid comparing vectors directly as much as possible,
		/// or use the <see cref = "CompareUsingTolerance(Vector3D,Vector3D,float)"/>
		/// method instead.
		/// </remarks>
		public static bool operator !=(Vector3D a, Vector3D b)
		{
			return a.x != b.x || a.y != b.y || a.z != b.z;
		}

		/// <summary>
		/// Compares the two vectors, using a default error tolerance of .001f
		/// </summary>
		/// <param name="a">The first operand</param>
		/// <param name="b">The second operand</param>
		/// <returns>True if the two vectors are equal, false otherwise.</returns>
		public static bool CompareUsingTolerance(Vector3D a, Vector3D b)
		{
			return Math.Abs(a.x - b.x) < .001f &&
				Math.Abs(a.y - b.y) < .001f &&
				Math.Abs(a.z - b.z) < .001f;
		}

		/// <summary>
		/// Compares the two vectors, using the given error tolerance.
		/// </summary>
		/// <param name="a">The first operand</param>
		/// <param name="b">The second operand</param>
		/// <param name="tolerance">The error tolerance. If two values differ less
		/// than this value, they are conidered equal.</param>
		/// <returns>True if the two vectors are equal, false otherwise.</returns>
		public static bool CompareUsingTolerance(Vector3D a, Vector3D b, float tolerance)
		{
			return Math.Abs(a.x - b.x) < tolerance &&
				Math.Abs(a.y - b.y) < tolerance &&
				Math.Abs(a.z - b.z) < tolerance;
		}

		/// <summary>
		/// Returns true if this vector equals the vector in obj.
		/// </summary>
		/// <param name="obj">An object that must be convertable to a vector.</param>
		/// <returns>True if the vectors are equal, false otherwise.</returns>
		public override bool Equals(object obj)
		{
			return this == (Vector3D)obj;
		}

		/// <summary>
		/// Returns a hashcod for this object.
		/// </summary>
		/// <returns>The hashcode</returns>
		public override int GetHashCode()
		{
			int xHash = x.GetHashCode();
			int yHash = y.GetHashCode();
			int zHash = z.GetHashCode();
			return xHash ^ ((yHash << 10) + (yHash >> 20)) ^ 
				((zHash << 20) + (zHash >> 10));
		}

		/// <summary>
		/// Gets the length of this vector
		/// </summary>
		public float Len
		{
			get
			{
				return (float)Math.Sqrt(x * x + y * y + z * z);
			}
		}

		/// <summary>
		/// Gets the squared length of this vector (Len ^ 2)
		/// </summary>
		public float SqrLen
		{
			get
			{
				return x * x + y * y + z * z;
			}
		}

		/// <summary>
		/// Normalizes this vector. ie. It will be scaled, so that it's
		/// length will be 1.
		/// </summary>
		public void Normalize()
		{
			float scale = 1 / (float)Math.Sqrt(x * x + y * y + z * z);
			x *= scale;
			y *= scale;
			z *= scale;
		}

		/// <summary>
		/// Scales this vector, so that it's length will be the given length.
		/// </summary>
		/// <param name="len">The length to scale this vector to.</param>
		public void Scale(float len)
		{
			float scale = len / (float)Math.Sqrt(x * x + y * y + z * z);
			x *= scale;
			y *= scale;
			z *= scale;
		}

		/// <summary>
		/// <para>
		/// Orthogonally projects this point to 2D, as seen from the front.
		/// </para>
		/// <para>
		/// This function creates a 2D vector, that uses the 3D x as 2D x,
		/// and the 3D y as 2D y. The z component is dropped.
		/// </para>
		/// </summary>
		/// <returns>The 2D vector that represents the frontal projection
		/// of this 3D vector.</returns>
		public Vector2D FromFront()
		{
			return new Vector2D(x, y);
		}

		/// <summary>
		/// <para>
		/// Orthogonally projects this point to 2D, as seen from the top.
		/// </para>
		/// <para>
		/// This function creates a 2D vector, that uses the 3D x as 2D x, 
		/// and the 3D z as 2D y. The y component is dropped.
		/// </para>
		/// </summary>
		/// <returns>The 2D vector that represents the top projection
		/// of this 3D vector.</returns>
		public Vector2D FromTop()
		{
			return new Vector2D(x, z);
		}

		/// <summary>
		/// <para>
		/// Orthogonally projects this point to 2D, as seen from the right.
		/// </para>
		/// <para>
		/// This function creates a 2D vector, that uses the 3D z as 2D x, 
		/// and the 3D y as 2D y. The x component is dropped.
		/// </para>
		/// </summary>
		/// <returns>The 2D vector that represents the projection from 
		/// the right side of this 3D vector.</returns>
		public Vector2D FromRight()
		{
			return new Vector2D(z, y);
		}

		/// <summary>
		/// Applies the given yaw rotation to this vector.
		/// </summary>
		/// <param name="angle">The yaw angle, in radians.</param>
		/// <seealso cref = "EulerRot"/>
		public void RotateYaw(float angle)
		{
			float s = (float)Math.Sin(angle);
			float c = (float)Math.Cos(angle);

			float rotX, rotZ;
			rotX = x * c - z * s;
			rotZ = x * s + z * c;
			x = rotX;
			z = rotZ;
		}

		/// <summary>
		/// Applies the given pitch rotation to this vector.
		/// </summary>
		/// <param name="angle">The pitch angle, in radians.</param>
		/// <seealso cref = "EulerRot"/>
		public void RotatePitch(float angle)
		{
			float s = (float)Math.Sin(angle);
			float c = (float)Math.Cos(angle);

			float rotY, rotZ;
			rotY = y * c + z * s;
			rotZ = y * -s + z * c;
			y = rotY;
			z = rotZ;
		}

		/// <summary>
		/// Applies the given roll rotation to this vector.
		/// </summary>
		/// <param name="angle">The roll angle, in radians.</param>
		/// <seealso cref = "EulerRot"/>
		public void RotateRoll(float angle)
		{
			float s = (float)Math.Sin(angle);
			float c = (float)Math.Cos(angle);

			float rotX, rotY;
			rotX = x * c - y * s;
			rotY = x * s + y * c;
			x = rotX;
			y = rotY;
		}

		/// <summary>
		/// Returns a float array that contains the 3 components of this vector.
		/// </summary>
		/// <remarks>
		/// This array is a copy of the components, so modifying it won't
		/// affect this vector directly. If you want to index this vector
		/// as an array, use the <see cref = "this[int]">indexer</see>
		/// of this array.
		/// </remarks>
		/// <returns>The array of components.</returns>
		public float[] ToFloatArray()
		{
			return new float[] { x, y, z };
		}

		/// <summary>
		/// <para>
		/// Calculates two vectors that are both perpendicular to this vector,
		/// and are also perpendicular to each other.
		/// </para>
		/// <para>
		/// If this vector has a length of 1, the output vectors are guaranteed
		/// to have a length of 1 aswell.
		/// </para>
		/// </summary>
		/// <param name="a">The output veriable for the first perpendicular vector.</param>
		/// <param name="b">The output veriable for the second perpendicular vector.</param>
		public void GetPerpVectors(out Vector3D a, out Vector3D b)
		{
			if ((float)Math.Abs(z) < .5f)
			{
				a.x = y;
				a.y = -x;
				a.z = 0;
				a *= 1 / (float)Math.Sqrt(x * x + y * y);

				b.x = a.y * z;
				b.y = -a.x * z;
				b.z = a.x * y - a.y * x;
			}
			else
			{
				a.x = 0;
				a.y = z;
				a.z = -y;
				a *= 1 / (float)Math.Sqrt(y * y + z * z);

				b.x = a.y * z - a.z * y;
				b.y = a.z * x;
				b.z = -a.y * x;
			}
		}

		/// <summary>
		/// Calculates the dotproduct of the 2 3D vectors.
		/// </summary>
		/// <param name="a">The first operand</param>
		/// <param name="b">The second operand</param>
		/// <returns>The result of the dotproduct operation.</returns>
		public static float DotProduct(Vector3D a, Vector3D b)
		{
			return a.x * b.x + a.y * b.y + a.z * b.z;
		}		

		/// <summary>
		/// Calculates the product of the 2 3D Vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the crossproduct operation.</returns>
		/// <remarks>
		/// When a triangle has it's vertices specified in the
		/// clockwise direction, the crossproduct of the first leg as 
		/// first operand, and the second leg as second operand will
		/// result in the normal of that triangle.
		/// </remarks>
		public static Vector3D CrossProduct(Vector3D a, Vector3D b)
		{
			return new Vector3D(
				a.y * b.z - a.z * b.y,
				a.z * b.x - a.x * b.z,
				a.x * b.y - a.y * b.x);
		}

		/// <summary>
		/// Linearily interpolates between the 2 vectors, using interpolation
		/// paramter <paramref name="t"/>
		/// </summary>
		/// <param name="a">The vector that corresponds to a param of 0</param>
		/// <param name="b">The vector that corresponds to a param of 1</param>
		/// <param name="t">The interpolation parameter, where 0 results in 
		/// the vector <paramref name="a"/>, and 1 results in the vector 
		/// <paramref name="b"/></param>
		/// <returns>The result of the interpolation</returns>
		public static Vector3D Interpolate(Vector3D a, Vector3D b, float t)
		{
			return a + (b - a) * t;
		}

		/// <summary>
		/// Gets a vector that points to the right (the positive x direction).
		/// </summary>
		public static Vector3D Right
		{
			get { return new Vector3D(1,0,0); }
		}

		/// <summary>
		/// Gets a vector that points upward (the positive y direction).
		/// </summary>
		public static Vector3D Up
		{
			get { return new Vector3D(0, 1, 0); }
		}

		/// <summary>
		/// Gets a string representation of this vector.
		/// </summary>
		/// <returns>The string representation of this vector.</returns>
		public override string ToString()
		{
			return x.ToString(CultureInfo.InvariantCulture) + ", " +
				y.ToString(CultureInfo.InvariantCulture) + ", " +
				z.ToString(CultureInfo.InvariantCulture);
		}

		[Dxml.ParseMethod]
		[ParseMethod]
		public static Vector3D Parse(string s)
		{
			string[] splitted = s.Split(",".ToCharArray());
			if (splitted.Length != 3)
				throw new Exception("A 3D vector should have 3 components.");

			return new Vector3D(
				float.Parse(splitted[0], CultureInfo.InvariantCulture),
				float.Parse(splitted[1], CultureInfo.InvariantCulture),
				float.Parse(splitted[2], CultureInfo.InvariantCulture));
		}

		public void WriteBinary(BinaryWriter writer)
		{
			writer.Write(x);
			writer.Write(y);
			writer.Write(z);
		}

		#region IXmlSerializable Members

		public System.Xml.Schema.XmlSchema GetSchema()
		{
			return null;
		}

		public void ReadXml(System.Xml.XmlReader reader)
		{
			Vector3D v = Parse(reader.ReadString());
			x = v.x;
			y = v.y;
			z = v.z;
		}

		public void WriteXml(System.Xml.XmlWriter writer)
		{
			writer.WriteString(ToString());
		}

		#endregion

#if XNA
		public static implicit operator Microsoft.Xna.Framework.Vector3(Vector3D vec)
		{
			return new Microsoft.Xna.Framework.Vector3(vec.x, vec.y, vec.z);
		}

		public static implicit operator Vector3D(Microsoft.Xna.Framework.Vector3 vec)
		{
			return new Vector3D(vec.X, vec.Y, vec.Z);
		}
#endif
	}

	/// <summary>
	/// A vector in a 4D, or 4D homogeneous space.
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct Vector4D
	{
		/// <summary>
		/// The x component of this vector.
		/// </summary>
		public float x;
		/// <summary>
		/// The y component of this vector.
		/// </summary>
		public float y;
		/// <summary>
		/// The z component of this vector.
		/// </summary>
		public float z;
		/// <summary>
		/// The w component of this vector.
		/// </summary>
		public float w;

		public float this[int i]
		{
			get
			{
#if SECURE
				if (i < 2)
				{
					if (x == 0)
						return x;
					else
						return y;
				}
				else
				{
					if (x == 2)
						return z;
					else
						return w;
				}
#else
#if PROTECTED
				if (i < 0 || i > 3)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector4D* pThis = &this)
					{
						return ((float*)pThis)[i];
					}
				}
#endif
			}

			set
			{
#if SECURE
				if (i < 2)
				{
					if (x == 0)
						x = value;
					else
						y = value;
				}
				else
				{
					if (x == 2)
						z = value;
					else
						w = value;
				}
#else
#if PROTECTED
				if (i < 0 || i > 3)
					throw new IndexOutOfRangeException();
#endif
				unsafe
				{
					fixed (Vector4D* pThis = &this)
					{
						((float*)pThis)[i] = value;
					}
				}
#endif
			}
		}

		public Vector4D(float x, float y, float z, float w)
		{
			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;
		}

		public void Set(float x, float y, float z, float w)
		{
			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;
		}

		/// <summary>
		/// Adds the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the addition.</returns>
		public static Vector4D operator +(Vector4D a, Vector4D b)
		{
			return new Vector4D(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
		}

		/// <summary>
		/// Subtracts the two vectors.
		/// </summary>
		/// <param name="a">The first operand.</param>
		/// <param name="b">The second operand.</param>
		/// <returns>The result of the subtraction.</returns>
		public static Vector4D operator -(Vector4D a, Vector4D b)
		{
			return new Vector4D(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
		}

		/// <summary>
		/// Multiplies the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the multiplication.</returns>
		public static Vector4D operator *(Vector4D a, float b)
		{
			return new Vector4D(a.x * b, a.y * b, a.z * b, a.w * b);
		}

		/// <summary>
		/// Divides the vector with the given scalar.
		/// </summary>
		/// <param name="a">The vector operand.</param>
		/// <param name="b">The scalar operand.</param>
		/// <returns>The result of the division.</returns>
		public static Vector4D operator /(Vector4D a, float b)
		{
			float reciB = 1 / b;
			return new Vector4D(a.x * reciB, a.y * reciB, a.z * reciB, a.w * reciB);
		}

		/// <summary>
		/// Normalizes this homogeneous coordinate to have a W of 1, ie. 
		/// all components will be divided by W.
		/// </summary>
		public void NormalizeW()
		{
			x /= w;
			y /= w;
			z /= w;
			w = 1;
		}

		public Vector3D ProjectTo3D()
		{
			return new Vector3D(x / w, y / w, z / w);
		}

		/// <summary>
		/// Returns a 3d vector made of the x,y and z components of this vector.
		/// </summary>
		/// <remarks>
		/// No homogeneous W divide is performed with this method. If you 
		/// want the 3D projection of this homogeneous vector, use the
		/// <see cref = "ProjectTo3D"/> method.
		/// </remarks>
		/// <returns>The 3D part of this vector</returns>
		public Vector3D Get3DPart()
		{
			return new Vector3D(x, y, z);
		}

		/// <summary>
		/// Gets a string representation of this vector.
		/// </summary>
		/// <returns>The string representation of this vector.</returns>
		public override string ToString()
		{
			return x.ToString(CultureInfo.InvariantCulture) + ", " +
				y.ToString(CultureInfo.InvariantCulture) + ", " +
				z.ToString(CultureInfo.InvariantCulture) + ", " +
				w.ToString(CultureInfo.InvariantCulture);
		}

		[ParseMethod]
		public static Vector4D Parse(string s)
		{
			string[] splitted = s.Split(",".ToCharArray());
			if (splitted.Length != 4)
				throw new Exception("A 4D vector should have 4 components.");

			return new Vector4D(
				float.Parse(splitted[0], CultureInfo.InvariantCulture),
				float.Parse(splitted[1], CultureInfo.InvariantCulture),
				float.Parse(splitted[2], CultureInfo.InvariantCulture),
				float.Parse(splitted[3], CultureInfo.InvariantCulture));
		}
	}
}